跳到主要内容

Nginx 限流控制

nginx 提供两种限流的方式:

  • 一是控制速率
  • 二是控制并发连接数

Nginx为我们提供了请求限制模块(ngx_http_limit_req_module)、基于令牌桶算法的流量限制模块(ngx_stream_limit_conn_module),可以方便的控制令牌速率,自定义调节限流,实现基本的限流控制…

漏桶算法控制速率限流

漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率示意图如下:

它也是解决雪崩的一种手段

请求限制

请求限制的功能来自于 ngx_http_limit_req_module 模块。使用它需要首先在 http 配置段中定义限制的参照标准和状态缓存区大小。

  • limit_req_zone 只能配置在 http 范围内;
  • $binary_remote_addr 表示客户端请求的IP地址;
  • mylimit 自己定义的变量名;
  • rate 请求频率,每秒允许多少请求;
  • limit_reqlimit_req_zone 对应,burst 表示缓存住的请求数,也就是任务队列。

配置只需在 Nginx 里面开辟一个空间,来做限流

http {
# 定义了一个 mylimit 缓冲区(容器),请求频率为每秒 1 个请求(nr/s)
# 例如:当 rate=10r/s 时,将 1s 拆成 10份,即每 100ms 可处理 1个请求
# mylimit 是缓存控制的名称(限流大小是 10m )
# $binary_remote_addr 表示根据用户 ip 进行限流
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;

server {
listen 70;
location / {
# nodelay 不延迟处理
# burst 是配置超额处理,可简单理解为队列机制
# 上面配置同一个 IP 每秒只能发送一次请求(1r/s),这里配置了缓存 3 个请求,就意味着同一秒内只能允许 4 个任务响应成功,其它任务请求则失败(503错误)
limit_req zone=mylimit burst=3 nodelay;
proxy_pass http://localhost:7070;
}
}
}

这里的 burst 译为突发、爆发,表示在超过设定的处理速率后能额外处理的请求数,例如,burst=4(rate=2r/s),若同时有 4 个请求到达,Nginx 会处理第一个请求, 剩余 3 个请求将放入队列,然后每隔 500ms 从队列中获取一个请求进行处理。若请求数大于 4,将拒绝处理多余的请求,直接返回 503。

不过,单独使用 burst 参数并不实用。假设 burst=50,rate 依然为 10r/s, 排队中的 50 个请求虽然每 100ms 会处理一个,但第 50个请求却需要等待 50 * 100ms 即 5s,这么长的处理时间自然难以接受。因此,burst 往往结合 nodelay(不延迟处理) 一起使用。

上图加上这个 nodelay 之后表示平均每秒允许不超过2个请求,突发不超过4个请求,并且处理突发4个请求的时候,没有延迟,等到完成之后,按照正常的速率处理。

控制并发量(连接数)

Nginx 并发限制的功能来自于 ngx_http_limit_conn_module 模块,跟请求配置一样,使用它之前,需要先定义参照标准和状态缓存区。

  • limit_conn_zone 只能配置在 http 范围内;
  • $binary_remote_addr 表示客户端请求的IP地址;
  • myconn 自己定义的变量名(缓冲区);
  • limit_rate 限制传输速度
  • limit_connlimit_conn_zone 对应,限制网络连接数

下面的配置就是定义了使用客户端的 IP 作为参照依据,并使用一个 10M 大小的状态缓存区。限定了每个IP只允许建立一个请求连接,同时传输的速度最大为 1024KB

# 定义了一个 myconn 缓冲区(容器)
limit_conn_zone $binary_remote_addr zone=myconn:10m;

server {
listen 70;
location / {
# 每个 IP 只允许一个连接
limit_conn myconn 1;
# 限制传输速度(如果有N个并发连接,则是 N * limit_rate)
limit_rate 1024k;
proxy_pass http://localhost:8080;
}
}

Reference